package map;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

/**
 * A terrain entry for use with the MapLibrary class.
 * Each entry has a unique identification number, a name,
 * an image, and a String for each edge. The edge Strings
 * should have two parts; the first should be a number and the second
 * should be a polarity (either 'a' or 'b'). Two terrain tiles
 * may be placed adjacent on a map if their touching edges
 * have the same number and opposite polarity. For example,
 * if the east edge of a tile is "7a", it may be placed on
 * the west edge of any tile with west edge "7b".
 * @author Alex Babis
 */
public class MapLibraryTerrainEntry implements Comparable<MapLibraryTerrainEntry>
{
	private int id;
	private String name;
	private Image image;
	private Image image90CW;
	private Image image180CW;
	private Image image270CW;
	private List<String> northEdges;
	private List<String> eastEdges;
	private List<String> southEdges;
	private List<String> westEdges;
	
	/**
	 * Builds a new terrain entry for a MapLibrary
	 * @param id		The unique ID for this entry
	 * @param name		The name of this entry
	 * @param image		The image associated with this entry
	 * @param northEdge	The String corresponding to the north edge of this terrain entry
	 * @param eastEdge	The String corresponding to the east edge of this terrain entry
	 * @param southEdge	The String corresponding to the south edge of this terrain entry
	 * @param westEdge	The String corresponding to the west edge of this terrain entry
	 */
	public MapLibraryTerrainEntry(int id, String name, Image image,
			String[] northEdges, String[] eastEdges, String[] southEdges, String[] westEdges)
	{
		this.id = id;
		this.name = name;
		this.image = image;
		image90CW = getRotatedImage(image);
		image180CW = getRotatedImage(image90CW);
		image270CW = getRotatedImage(image180CW);
		this.northEdges = new ArrayList<String>();
		for(String string : northEdges)
			this.northEdges.add(string);
		this.eastEdges = new ArrayList<String>();
		for(String string : eastEdges)
			this.eastEdges.add(string);
		this.southEdges = new ArrayList<String>();
		for(String string : southEdges)
			this.southEdges.add(string);
		this.westEdges = new ArrayList<String>();
		for(String string : westEdges)
			this.westEdges.add(string);
	}

	// Thanks to:
	// http://stackoverflow.com/questions/706665/lossless-jpeg-rotate-90-180-270-degrees-in-java
	/**
	 * Returns an Image that is a rotated copy of given image
	 * @param image The Image to be rotated
	 * @return A rotated copy of given image
	 */
	private Image getRotatedImage(Image image)
	{
		Image rotatedImage = new BufferedImage(image.getHeight(null),
				image.getWidth(null), BufferedImage.TYPE_INT_ARGB);

	    Graphics2D g2d = (Graphics2D) rotatedImage.getGraphics();
	    g2d.rotate(Math.toRadians(90.0));
	    g2d.drawImage(image, 0, -rotatedImage.getWidth(null), null);
	    g2d.dispose();
	    return rotatedImage;
	}
	
	/** Compares this entry to another
	 * @return True if the id of this entry equals that of the other; false otherwise */
	public boolean equals(Object other){return ((MapLibraryTerrainEntry)other).id == id;}
	
	/** Compares this entry to another
	 * @return An integer comparing these two entries */
	public int compareTo(MapLibraryTerrainEntry other){return id - other.id;}
	
	/** Gets the ID of this terrain entry
	 * @return The unique ID for this terrain entry */
	public int getID(){return id;}
	
	/** Gets the name of this terrain entry
	 * @return The name of this terrain entry */
	public String getName(){return name;}
	
	/** Gets the Image for this terrain entry
	 * @return The Image for this terrain entry */
	public Image getImage(){return image;}

	/** Gets the Image for this terrain entry
	 * @return The Image for this terrain entry */
	public Image getImage(int rotation)
	{
		switch(rotation)
		{
			case 0:
				return image;
			case 1:
				return image90CW;
			case 2:
				return image180CW;
			case 3:
				return image270CW;
		}
		return null;
	}
	
	/** Gets the String for the north edge of this terrain entry
	 * @return The String corresponding to the north edge of this terrain entry */
	public List<String> getNorthEdges(){return northEdges;}
	
	/** Gets the String for the east edge of this terrain entry
	 * @return The String corresponding to the east edge of this terrain entry */
	public List<String> getEastEdges(){return eastEdges;}
	
	/** Gets the String for the south edge of this terrain entry
	 * @return The String corresponding to the south edge of this terrain entry */
	public List<String> getSouthEdges(){return southEdges;}
	
	/** Gets the String for the west edge of this terrain entry
	 * @return The String corresponding to the west edge of this terrain entry */
	public List<String> getWestEdges(){return westEdges;}

	/** Gets the String for the north edge of this terrain entry
	 * when the tile is rotated by the given amount
	 * @return The String corresponding to the north edge of this terrain entry 
	 * when the tile is rotated by the given amount*/
	public List<String> getNorthEdges(int rotation)
	{
		switch(rotation)
		{
			case 0:
				return northEdges;
			case 1:
				return westEdges;
			case 2:
				return southEdges;
			default: // 3
				return eastEdges;
		}
	}
	
	/** Gets the String for the east edge of this terrain entry
	 * when the tile is rotated by the given amount
	 * @return The String corresponding to the east edge of this terrain entry
	 * when the tile is rotated by the given amount */
	public List<String> getEastEdges(int rotation)
	{
		switch(rotation)
		{
			case 0:
				return eastEdges;
			case 1:
				return northEdges;
			case 2:
				return westEdges;
			default: // 3
				return southEdges;
		}
	}
	
	/** Gets the String for the south edge of this terrain entry
	 * when the tile is rotated by the given amount
	 * @return The String corresponding to the south edge of this terrain entry
	 * when the tile is rotated by the given amount */
	public List<String> getSouthEdges(int rotation)
	{
		switch(rotation)
		{
			case 0:
				return southEdges;
			case 1:
				return eastEdges;
			case 2:
				return northEdges;
			default: // 3
				return westEdges;
		}
	}
	
	/** Gets the String for the west edge of this terrain entry
	 * when the tile is rotated by the given amount
	 * @return The String corresponding to the west edge of this terrain entry
	 * when the tile is rotated by the given amount */
	public List<String> getWestEdges(int rotation)
	{
		switch(rotation)
		{
			case 0:
				return westEdges;
			case 1:
				return southEdges;
			case 2:
				return eastEdges;
			default: // 3
				return northEdges;
		}
	}

	/** Gets a List of the edge Strings for this entry
	 * @return A list of edge Strings for this entry */
	public List<String> getEdges()
	{
		ArrayList<String> edges = new ArrayList<String>();
		edges.addAll(northEdges);
		edges.addAll(eastEdges);
		edges.addAll(southEdges);
		edges.addAll(westEdges);
		return edges;
	}
	
	/** Gets a String representation of this entry
	 * @return A String representation of this entry */
	public String toString(){return id + " " + name
		+ "North:" + northEdges + "East:" + eastEdges + "South:" + southEdges + "West:" + westEdges;}
}